//
//  TWVideoPlayerController.swift
//  EyepetizerImitative
//
//  Created by 田伟 on 2017/3/23.
//  Copyright © 2017年 个人. All rights reserved.
//  全屏播放器

import UIKit
import SnapKit
import AVFoundation

class TWVideoPlayerController: UIViewController {

    // MARK:- 懒加载
    // 播发器
    fileprivate lazy var player : AVPlayer = AVPlayer()                                                                 // 播放器
    fileprivate lazy var playerLayer : AVPlayerLayer = AVPlayerLayer()                                                  // 播放器需要的layer
    // 视图
    fileprivate lazy var backView : UIView = UIView()                                                                   // 最底层的View
    fileprivate lazy var topView : UIView = UIView()                                                                    // 顶部的View
    fileprivate lazy var closeButton : UIButton = UIButton()                                                            // 顶部View中的关闭按钮
    fileprivate lazy var titleLabel : UILabel = UILabel()                                                               // 顶部View中的标题label
    // 底部
    fileprivate lazy var bottomView : UIView = UIView()                                                                 // 底部的View
    fileprivate lazy var playButton : UIButton = UIButton()                                                             // 底部View中的播放按钮
    fileprivate lazy var fullScreenButton : UIButton = UIButton()                                                       // 底部View中的全屏按钮
    fileprivate lazy var nowLabel : UILabel = UILabel()                                                                 // 底部View中的已播时间label
    fileprivate lazy var remainLabel : UILabel = UILabel()                                                              // 底部View中的剩余时间label
    fileprivate lazy var progressView : UIProgressView = UIProgressView()                                               // 底部View中的缓存进度条
    fileprivate lazy var slider : UISlider = UISlider()                                                                 // 底部View中的播放进度条
    fileprivate lazy var autoDismissTimer : Timer = Timer()                                                             // 定时器 自动消失View

    
    // MARK:- 属性
    var playerItem : AVPlayerItem?                                                                                      // 播放器属性对象
    var isDragSlider : Bool = false                                                                                     // 是否拖动Slider
    var palyModel : TWItemModel?{
        didSet {
            guard let palyModel = palyModel else {
                return
            }
            videoUrl = URL(string: palyModel.playUrl!)
            titleStr = palyModel.title
        }
    }
    var videoUrl : URL?
    var titleStr : String?

    /// 隐藏状态栏是模态切换的话，那么切换的样式不能是.custom类型否则不起作用
    override var prefersStatusBarHidden: Bool{
        return true
    }
    // MARK:- 系统回调函数
    override func viewDidLoad() {
        super.viewDidLoad()
        setupBackView()
        setupTopView()
        setupBottomView()
        initPlayer()
    }
    deinit{
        TWLog(message: "播发器内存释放掉了")
        playerLayer.removeFromSuperlayer()
        playerItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
        playerItem?.removeObserver(self, forKeyPath: "status")
    }
}


// MARK:- 搭建UI界面
extension TWVideoPlayerController {
    // 处理背景视图
    fileprivate func setupBackView(){
        // 翻转
        self.backView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(M_PI_2))
        backView.frame = CGRect(x: 0, y: 0, width: TWScreenWidth, height: TWScreenHeight)
        backView.backgroundColor = UIColor.black
        let tap = UITapGestureRecognizer(target: self, action: #selector(backViewSingleTap))
        backView.addGestureRecognizer(tap)
        view.addSubview(backView)
    }
    // 设置顶部View
    fileprivate func setupTopView(){
        topView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.8)
        backView.addSubview(topView)
        /**
         backView向左边翻转了90度，backView的frame中，宽和高不不变
         内部子控件的影响：
         topView  x 轴变成了 从底部向上的间距
         y 轴变成了 从左边向右边的间距
         w 变成了高度
         h 变成了宽度
         */
        topView.snp.makeConstraints { (make) in
            make.top.left.equalTo(backView)
            make.width.equalTo(backView.snp.height)
            make.height.equalTo(50)
        }
        closeButton.setImage(UIImage(named: "btn_back_normal"), for: .normal)
        closeButton.showsTouchWhenHighlighted = true    // 用户手指接触的部分会发亮
        closeButton.addTarget(self, action: #selector(closeButtonClick), for: .touchUpInside)
        topView.addSubview(closeButton)
        closeButton.snp.makeConstraints { (make) in
            make.left.equalTo(topView).offset(5)
            make.centerY.equalTo(topView)
            make.width.height.equalTo(30)
        }
        titleLabel.textAlignment = .left
        titleLabel.textColor = UIColor.white
        titleLabel.font = UIFont.systemFont(ofSize: 17)
        titleLabel.text = titleStr
        topView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { (make) in
            make.left.equalTo(closeButton.snp.right).offset(10)
            make.centerY.equalTo(topView)
            make.right.equalTo(topView).offset(-20)
            make.height.equalTo(30)
        }
    }
    // 设置底部View
    fileprivate func setupBottomView(){
        bottomView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
        backView.addSubview(bottomView)
        bottomView.snp.makeConstraints { (make) in
            make.left.equalTo(backView)
            make.bottom.equalTo(TWScreenWidth - TWScreenHeight)
            make.width.equalTo(backView.snp.height)
            make.height.equalTo(50)
        }
        playButton.setImage(UIImage(named: "action_player_play_80x80_"), for: .normal)
        playButton.showsTouchWhenHighlighted = true    // 用户手指接触的部分会发亮
        playButton.addTarget(self, action: #selector(pauseOrPlayButtonClick), for: .touchUpInside)
        bottomView.addSubview(playButton)
        playButton.snp.makeConstraints { (make) in
            make.left.equalTo(bottomView).offset(5)
            make.centerY.equalTo(bottomView)
            make.width.height.equalTo(50)
        }
        fullScreenButton.setImage(UIImage(named: "fullscreen"), for: .normal)
        fullScreenButton.showsTouchWhenHighlighted = true    // 用户手指接触的部分会发亮
        fullScreenButton.addTarget(self, action: #selector(fullScreenButtonClick), for: .touchUpInside)
        bottomView.addSubview(fullScreenButton)
        fullScreenButton.snp.makeConstraints { (make) in
            make.right.equalTo(bottomView).offset(5)
            make.centerY.equalTo(bottomView)
            make.width.height.equalTo(50)
        }
        slider.minimumValue = 0.0
        slider.value = 0.0
        slider.minimumTrackTintColor = UIColor.white
        slider.maximumTrackTintColor = UIColor.lightGray
        slider.setThumbImage(UIImage(named: "player_handle"), for: .normal)
        // 拖动滑块改变值
        slider.addTarget(self, action: #selector(sliderDragValueChange(slider:)), for: .valueChanged)
        // 点击进度条上的某个位置改变值
        slider.addTarget(self, action: #selector(sliderTapValueChange(slider:)), for: .touchUpInside)
        // 增加手势
        let sliderTap = UITapGestureRecognizer(target: self, action: #selector(touchSlider(tap:)))
        slider.addGestureRecognizer(sliderTap)
        bottomView.addSubview(slider)
        slider.snp.makeConstraints { (make) in
            make.left.equalTo(playButton.snp.right).offset(5)
            make.right.equalTo(fullScreenButton.snp.left).offset(5)
            make.centerY.equalTo(bottomView)
        }
        progressView.trackTintColor = UIColor.cyan
        progressView.progressTintColor = UIColor.red
        progressView.setProgress(0.0, animated: false)
        bottomView.addSubview(progressView)
        progressView.snp.makeConstraints { (make) in
            make.left.equalTo(slider)
            make.right.equalTo(slider)
            make.height.equalTo(2)
            make.centerY.equalTo(slider.snp.centerY).offset(1)
        }
        bottomView.sendSubview(toBack: progressView)
        // 时间显示
        nowLabel.textColor = UIColor.white
        nowLabel.font = UIFont.systemFont(ofSize: 13)
        nowLabel.textAlignment = .left
        bottomView.addSubview(nowLabel)
        nowLabel.snp.makeConstraints { (make) in
            make.left.equalTo(slider)
            make.bottom.equalTo(bottomView)
            make.size.equalTo(CGSize(width: 100, height: 20))
        }
        remainLabel.textColor = UIColor.white
        remainLabel.font = UIFont.systemFont(ofSize: 13)
        remainLabel.textAlignment = .right
        bottomView.addSubview(remainLabel)
        remainLabel.snp.makeConstraints { (make) in
            make.right.equalTo(slider)
            make.bottom.equalTo(bottomView)
            make.size.equalTo(CGSize(width: 100, height: 20))
        }
    }
}

// MARK:- 初始化播放器
extension TWVideoPlayerController {
    fileprivate func initPlayer(){
        playerItem = AVPlayerItem(url: videoUrl!)
        player = AVPlayer(playerItem: playerItem)
        // 初始化播放器的Layer
        playerLayer = AVPlayerLayer(player: player)
        
        // layer的方向宽和高对调
        playerLayer.frame = CGRect(x: 0, y: 0, width: TWScreenHeight, height: TWScreenWidth)
        
        playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill          // // 等比例拉伸，会裁剪
        // 把layer加到底部的view上
        backView.layer.insertSublayer(playerLayer, at: 0)
        // 监听
        playerItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
        playerItem?.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)
    }
}


// MARK:- 监听点击
extension TWVideoPlayerController {
    // 轻按背景视图backView
    @objc fileprivate func backViewSingleTap(){
        // 删除之前未执行的操作
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(autoDismissView), object: nil)
        // 这里点击会隐藏对应的View，那么之前的定时还开着，如果不关掉，就会可能重复
        autoDismissTimer.invalidate()       // 关掉定时器
        // 再重新打开定时器
        autoDismissTimer = Timer.init(timeInterval: 8.0, target: self, selector: #selector(autoDismissView), userInfo: nil, repeats: true)
        RunLoop.current.add(autoDismissTimer, forMode: .defaultRunLoopMode)
        // 更改UI
        UIView.animate(withDuration: 1.0) {
            if self.bottomView.alpha == 1 {
                self.bottomView.alpha = 0
                self.topView.alpha = 0
            } else if self.bottomView.alpha == 0 {
                self.bottomView.alpha = 1
                self.topView.alpha = 1
            }
        }
    }
    // 点击返回按钮
    @objc fileprivate func closeButtonClick(){
      
        autoDismissTimer.invalidate()
        player.currentItem?.cancelPendingSeeks()
        player.currentItem?.asset.cancelLoading()
        player.replaceCurrentItem(with: nil)
        dismiss(animated: true, completion: nil)
    }
    // 点击播放或者暂停按钮
    @objc fileprivate func pauseOrPlayButtonClick(){
        if player.rate != 1 {
            playButton.setImage(UIImage(named: "action_player_pause_80x80_"), for: .normal)
            player.play()
        } else {
            playButton.setImage(UIImage(named: "action_player_play_80x80_"), for: .normal)
            player.pause()
        }
    }
    // 点击全屏播放
    @objc fileprivate func fullScreenButtonClick(){
        closeButtonClick()
    }
    // 进度条的滑块拖拽的时候调用,这个时候不更新视频进度
    @objc fileprivate func sliderDragValueChange(slider : UISlider){
        isDragSlider = true
    }
    // 点击调用  或者 拖拽完毕的时候调用
    @objc fileprivate func sliderTapValueChange(slider : UISlider){
        isDragSlider = false
        let cmtime = CMTime(seconds: Double(slider.value), preferredTimescale: (playerItem?.currentTime().timescale)!)
        player.seek(to: cmtime)
    }
    // 点击事件的Slider
    @objc fileprivate func touchSlider(tap : UITapGestureRecognizer){
        let touch = tap.location(in: slider)
        let scale = touch.x / slider.bounds.size.height      // 根据点击的坐标计算对应的比例
        let duration = Float(CMTimeGetSeconds((playerItem?.duration)!))
        slider.value = duration * Float(scale)
        let cmtime = CMTime(seconds: Double(slider.value), preferredTimescale: (playerItem?.currentTime().timescale)!)
        player.seek(to: cmtime)
        if player.rate != 1 {               // 0.0 means "stopped", 1.0 means "play
            playButton.setImage(UIImage(named: "action_player_pause_80x80_"), for: .normal)
            player.play()
        }
    }
    // 监听播放器的变化属性
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let playerItem = object as? AVPlayerItem else {
            return
        }
        if keyPath == "status" {
            if playerItem.status == .readyToPlay {
            
                pauseOrPlayButtonClick()
                // 最大值直接用sec，以前都是
                // CMTimeMake(帧数（slider.value * timeScale）, 帧/sec)
                slider.maximumValue = Float(CMTimeGetSeconds(playerItem.duration))
                self.initTimer()
                // 启动定时器 5秒自动隐藏
                autoDismissTimer = Timer.init(timeInterval: 8.0, target: self, selector: #selector(autoDismissView), userInfo: nil, repeats: true)
                RunLoop.current.add(autoDismissTimer, forMode: .defaultRunLoopMode)
            } else {
                print("视频加载异常")
            }
        } else if keyPath == "loadedTimeRanges" {
            let timeInterval = availableDuration()
            let duration = playerItem.duration
            let durationTime = CMTimeGetSeconds(duration)
            // 给进度条赋值
            let progress = timeInterval / durationTime
            progressView.setProgress(Float(progress), animated: false)
        }
    }
    // 自动隐藏backView
    @objc private func autoDismissView(){
        if player.rate == 0 {
            // 0表示暂停状态，不隐藏
        } else if player.rate == 1 {// 1表示播放中
            if bottomView.alpha == 1 {
                UIView.animate(withDuration: 1.0, animations: {
                    self.bottomView.alpha = 0
                    self.topView.alpha = 0
                })
            }
        }
    }
}


// MARK:- 自定义方法
extension TWVideoPlayerController {
    // 调用plaer的对象进行UI更新
    fileprivate func initTimer(){
        let cmtime = CMTime(value: 1, timescale: 1)
        // 播放器用addPeriodicTimeObserverForInterval设定每隔1秒监控播放时间变化,每秒更新一次UI Slider
        player.addPeriodicTimeObserver(forInterval: cmtime, queue: DispatchQueue.main) { [weak self] (_) in
            let now = CMTimeGetSeconds((self?.playerItem?.currentTime())!)               // 当前时间
            let duration = CMTimeGetSeconds((self?.playerItem?.duration)!)               // 总时间
            // 转成时间点
            self?.nowLabel.text = self?.convertToTime(time: CGFloat(now))
            let timeDifference = CGFloat(duration - now)
            self?.remainLabel.text = self?.convertToTime(time: timeDifference)
            // 不是拖拽中的话更新UI
            if !(self?.isDragSlider)! {
                self?.slider.value = Float(now)
            }
        }
    }
    // 将秒数转换成 00:00 的格式
    private func convertToTime(time : CGFloat) -> String{
        var timeStr : String = ""
        if time >= 3600 {
            // 超过一小时
            let hour = Int(time / 3600)
            let minutes = Int((time / 60).truncatingRemainder(dividingBy: 60))
            let seconds = Int(time.truncatingRemainder(dividingBy: 60))
            timeStr = String(format: "%02d:%02d:%02d", hour, minutes, seconds)
            return timeStr
        } else {
            let minutes = Int(time / 60)
            let seconds = Int(time.truncatingRemainder(dividingBy: 60))
            timeStr = String(format: "%02d:%02d", minutes, seconds)
            return timeStr
        }
    }
    // 计算缓冲进度
    fileprivate func availableDuration() -> TimeInterval {
        let loadedTimeRanges = playerItem?.loadedTimeRanges
        // 获取缓冲区域
        let timeRange = loadedTimeRanges?.first?.timeRangeValue
        // 开始的点
        let startSeconds = CMTimeGetSeconds((timeRange?.start)!)
        // 已缓存的时间点
        let durationSeconds = CMTimeGetSeconds((timeRange?.duration)!)
        // 计算缓冲总进度
        let result = startSeconds + durationSeconds
        return TimeInterval(result)
    }
}





